package XOrules;

import java.util.*;
import java.lang.*;
import java.math.*;

public class XOrulesUtilits {
    public final static Character Xchar = 'X';
    public final static Character Ochar = 'O';
    public final static Character Fchar = '-';
    public final static Character NBchar = 'N';

    public static Vector<Character> createField(int l)
    {
        Vector<Character> res = new Vector<Character>(l * l);
        for (int i = 0; i < l*l; ++i)
            res.add(XOrulesUtilits.Fchar);
        return res;
    }

    public static int getLfield(Vector<Character> fld)
    {
        return (int)Math.sqrt(fld.size());
    }

    public static Character whoseTurn(Vector<Character> fld)
    {
        int Xcount = 0;
        for (Character x: fld)
            if (x == Xchar)
                ++Xcount;
        int Ocount = 0;
        for (Character x: fld)
            if (x == Ochar)
                ++Ocount;
        if (Xcount > Ocount)
            return Ochar;
        return Xchar;
    }

    public static boolean isItTurn(Vector<Character> fld, Character who, int x, int y)
    {
        if (x<0 || y<0)
            return false;
        int l = getLfield(fld);
        if ((x+1) > l || (y+1) > l)
            return false;

        if (fld.get(y*l + x) != Fchar)
            return false;

        Character whoseTrn = whoseTurn(fld);
        if (whoseTrn != who)
		    return false;

        return true;
    }

    public static void makeTurn(Vector<Character> fld, Character who, int x, int y)
    {
	    int l = getLfield(fld);
	    fld.set(y*l + x, who);
    }

    public static Character whoseWin(Vector<Character> fld)
    {
        return whoseWin(fld, 0);
    }

    public static Character whoseWin(Vector<Character> fld, int minChain)
    {
        int Fcount = 0;
        for (Character x : fld) {
            if (x != Fchar)
                ++Fcount;
        }
        if (Fcount >= fld.size())
            return NBchar;

        if (minChain == 0)
            minChain = getLfield(fld);
        Vector<Vector<Character>> chains = getChains(fld, minChain);
        for (Vector<Character> chain : chains) {
            Character res = lambda_chain_find(chain, minChain);
            if (res != Fchar)
                return res;
        }
        return Fchar;
    }

    private static Character lambda_chain_find(Vector<Character> chain, int minChain)
    {
        Character res = Fchar;
        int count = 0;
        for(Character c : chain)
        {
            if (c == Fchar)
            {
                res = Fchar;
                count = 0;
            }
            if (c == res)
            {
                count += 1;
                if (count >= minChain)
                    return res;
            }
            else
            {
                res = c;
                count = 1;
            }
        }
        return Fchar;
    }

    private static Vector<Vector<Character>> getChains(Vector<Character> fld, int minChain)
    {
        Vector<Vector<Character>> res = new Vector<Vector<Character>>();
        int l = getLfield(fld);
        for (int i = 0; i < l; ++i)
        {
            res.add(getChain(fld, 0, i, +1, 0));
            res.add(getChain(fld, i, 0, 0, +1));
        }
        for (int x = 0; x < (l-minChain+1); ++x)
            for (int y = 0; y <(l-minChain+1); ++y)
            {
                if ((x==0) || (y==0))
                    res.add(getChain(fld, x, y, +1, +1));
                if ((x==0) || (y==0))
                    res.add(getChain(fld, l-x-1, y, -1, +1));
            }
        return res;
    }

    private static Vector<Character> getChain(Vector<Character> fld, int x, int y, int dx, int dy)
    {
        Vector<Character> res = new Vector<Character>();

        int l = getLfield(fld);

        while (x < l && y < l && x>=0 && y>=0)
        {
            res.add(fld.get(y*l+x));
            x += dx;
            y += dy;
        }
        return res;
    }
}
